package com.guru.adapter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.ClasspathPropertiesFileCredentialsProvider;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.TableCollection;
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
import com.amazonaws.services.dynamodbv2.model.GetItemResult;
import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
import com.amazonaws.services.dynamodbv2.model.KeyType;
import com.amazonaws.services.dynamodbv2.model.ListTablesResult;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.model.PutItemResult;
import com.amazonaws.services.dynamodbv2.model.TableDescription;

public class GuruDynamoAdapter {
	private static GuruDynamoAdapter classInstance = new GuruDynamoAdapter();
	private AmazonDynamoDBClient dbClient;
	private String TBL_TOPSKILLS = "topskills";
	private DynamoDB dynamoDB; 
			//new DynamoDB(new AmazonDynamoDBClient(new ProfileCredentialsProvider()));
	
	private GuruDynamoAdapter() {
		 AWSCredentialsProvider credentialsProvider = new ClasspathPropertiesFileCredentialsProvider();
	     dbClient = new AmazonDynamoDBClient(credentialsProvider);
	     dynamoDB = new DynamoDB(dbClient);
	}
	
	public static GuruDynamoAdapter getInstance() {
		return classInstance;
	}
	
	public void deleteTable(String tableName) throws InterruptedException{
		Table table = dynamoDB.getTable(tableName);
		System.out.println("Deleting table: "+tableName);
		table.delete();
		System.out.println("Waiting for delete to complete.");
		table.waitForDelete();
		System.out.println("Done. Delete completed.");
	}
	
	public void listTables(){
		
		TableCollection<ListTablesResult> tables = dynamoDB.listTables();
		Iterator<Table> iterator = tables.iterator();
		System.out.println("Listing all tables in DynamoDB:");
		while (iterator.hasNext()) {
			Table table = iterator.next();
			System.out.println(table.getTableName());
		}
	}
	
	public void describeTable(String tableName){
		
		TableDescription tableDescription = 
			    dynamoDB.getTable(tableName).describe();
		System.out.println("Describing table: "+tableName);
		System.out.printf("%s: %s \t ReadCapacityUnits: %d \t WriteCapacityUnits: %d",
		    tableDescription.getTableStatus(),
		    tableDescription.getTableName(),
		    tableDescription.getProvisionedThroughput().getReadCapacityUnits(),
		    tableDescription.getProvisionedThroughput().getWriteCapacityUnits());
	}
	
	public void createTable(String tableName) throws InterruptedException{

		ArrayList<AttributeDefinition> attributeDefinitions= new ArrayList<AttributeDefinition>();
		attributeDefinitions.add(new AttributeDefinition().withAttributeName("Id").withAttributeType("N"));

		ArrayList<KeySchemaElement> keySchema = new ArrayList<KeySchemaElement>();
		keySchema.add(new KeySchemaElement().withAttributeName("Id").withKeyType(KeyType.HASH));
		        
		CreateTableRequest request = new CreateTableRequest()
				.withTableName(tableName)
				.withKeySchema(keySchema)
				.withAttributeDefinitions(attributeDefinitions)
				.withProvisionedThroughput(new ProvisionedThroughput()
				    .withReadCapacityUnits(5L)
					.withWriteCapacityUnits(6L));

		System.out.println("Creating table: "+tableName);
		Table table1 = dynamoDB.createTable(request);
		System.out.println("Waiting for table to be active.");
		table1.waitForActive();
		System.out.println("Done. Table created successfully.");
	}
	
	public void addSkillToCategory(String category, String skill){
		Map<String, AttributeValue>	item = getSkillsForCategory(category);
		if(item == null){
			item = new HashMap<String, AttributeValue>();
			item.put("category", new AttributeValue().withS(category.toLowerCase()));
			item.put("skill", new AttributeValue().withSS(skill));
		}else{
			Set<String> skillSet = new HashSet<String>(item.get("skill").getSS());
			skillSet.add(skill);
			item.put("skill", new AttributeValue().withSS(skillSet));
		}
		
		System.out.println("Adding item to topskills table : "+item);
		PutItemResult result = dbClient.putItem(TBL_TOPSKILLS, item);
		System.out.println("Result: "+ result);
	}
	
	public Map<String, AttributeValue> getSkillsForCategory(String category){
		Map<String, AttributeValue>	lookupItem = new HashMap<>();{
			lookupItem.put("category", new AttributeValue().withS(category.toLowerCase()));
		}
		
		System.out.println("Looking up for skills for a category :"+lookupItem);
		GetItemResult result = dbClient.getItem(new GetItemRequest(this.TBL_TOPSKILLS, lookupItem));
		System.out.println("Result: "+ result.getItem());
		return result.getItem();
	}
	
	public static void main(String[] args) {
		GuruDynamoAdapter db = GuruDynamoAdapter.getInstance();
		String category = "sports";
		db.addSkillToCategory(category, "Cricket Boss");
		db.addSkillToCategory(category, "Soccer Boss");
		db.getSkillsForCategory(category);
		db.getSkillsForCategory("movies");
	}
}
